.com
Hosted by:
Unit testing expertise at your fingertips!
Home | Discuss | Lists

Implicit Teardown

The book has now been published and the content of this chapter has likely changed substanstially.
Please see page 516 of xUnit Test Patterns for the latest information.
Also known as: Hooked Teardown, Framework-invoked Teardown, Teardown Method

How do we tear down the Test Fixture?

The Test Automation Framework calls our clean up logic in the tearDown method after every Test Method.

Sketch Implicit Teardown embedded from Implicit Teardown.gif

A large part of making tests repeatable and robust is ensuring that the test fixture is torn down after each test. Leftover objects and database records, open files and connections can at best cause performance degradations and at worst cause tests to fail or systems to crash.

When we can't take advantage of Garbage-Collected Teardown (page X) and we have several tests with the same objects to tear down, we can put the tear down clogic into a special tearDown method that the Test Automation Framework (page X) calls after each Test Method (page X) is run.

How It Works

Anything that needs to be cleaned up can be freed or destroyed in the final phase of the Four-Phase Test (page X), namely the fixture teardown phase. Most members of the XUnit family of Test Automation Frameworks support the concept of Implicit Teardown wherein they call the tearDown method of each Testcase Object (page X) after the Test Method has been run.

The tearDown method is called regardless of whether the test passes or fails. This ensures that we have the opportunity to clean up undisturbed by any failed assertions. Beware, however, that some members of the family do not call tearDown if the setUp method raises an error.

When To Use It

We can use Implicit Teardown whenever we have several tests with the same resources that need to be destroyed or freed explicitly after the test has been completed and those resources will not be destroyed or freed automatically. We may discover this because we have Unrepeatable Tests (see Erratic Test on page X) or Slow Tests (page X) caused by the accumulation of detritus from many test runs.

If the objects created by the test are internal resources and subject to automated memory management then Garbage-Collected Teardown may eliminate a lot of work for us. If each test has a completely different set of objects to teardown then Inline Teardown (page X) may be more appropriate. In many cases, manually written teardown logic can be avoided entirely with Automated Teardown (page X).

Implementation Notes

The teardown logic in the tearDown method is most commonly discovered by refactoring from tests that had Inline Teardown. The tearDown method may need to be "flexible" or "accomodating" for several reasons:

Variation: Teardown Guard Clause

We can avoid arbitrarily Conditional Test Logic (page X) to deal with the case where only a subset of the objects to be torn down are actually present by putting a guard clause (a simple if statement) around each tear down operation to guard against the resource not being present. Given this technique, a suitably coded tearDown method can tear down various fixture configurations. Contrast this with the setUp method which can only set up the lowest common denominator fixture for the Test Methods that share it.

Motivating Example

The test below sets up several standard objects during fixture setup. Because the objects are persisted in a database, they must be cleaned up explicitly after every test. Each test (I have only shown one of severeal) contains the same inline teardown logic to delete the objects.

   public void testGetFlightsByOrigin_NoInboundFlight_SMRTD() throws Exception {
      // Fixture setup
      BigDecimal outboundAirport = createTestAirport("1OF");
      BigDecimal inboundAirport = null;
      FlightDto expFlightDto = null;
      try {
         inboundAirport = createTestAirport("1IF");
         expFlightDto = createTestFlight(outboundAirport, inboundAirport);
         // Exercise System
         List flightsAtDestination1 = facade.getFlightsByOriginAirport(inboundAirport);
         // Verify Outcome
         assertEquals(0,flightsAtDestination1.size());
      } finally {
         try {
            facade.removeFlight(expFlightDto.getFlightNumber());
         } finally {
            try {
               facade.removeAirport(inboundAirport);
            } finally  {
               facade.removeAirport(outboundAirport);
            } 
         }             
      }           
   }
Example SafeMultiResourceGuaranteedTeardown embedded from java/com/clrstream/ex6/services/test/InlineTeardownExampleTest.java

There is enough Test Code Duplication (page X) here to warrant converting these tests to Implicit Teardown.

Refactoring Notes

First, we find the most representative example of teardown in all the tests. Then, we do an Extract Method[Fowler] refactoring on that code and call the resulting method tearDown. Finally, we delete the teardown logic in each of the other tests. We may need to introduce Teardown Guard Clauses around any tear down logic that may not be needed in every test. We should also surround each tear down attempt with a try/finally to ensure the remaining teardown logic executes even if an earlier one fails.

Example: Implicit Teardown

In this example, we see the same tests with the teardown logic moved to the tearDown method. We have also introduced a series of nested try/finally blocks around teardown operations to make sure that a error raised in one doesn't prevent the remaining ones from being executed. Note how much smaller the tests have become.

   BigDecimal outboundAirport;
   BigDecimal inboundAirport;
   FlightDto expFlightDto;
  
   public void testGetFlightsByAirport_NoInboundFlights_NIT() throws Exception {
      // Fixture setup
      outboundAirport = createTestAirport("1OF");
      inboundAirport = createTestAirport("1IF");
      expFlightDto = createTestFlight( outboundAirport, inboundAirport);
      // Exercise System
      List flightsAtDestination1 = facade.getFlightsByOriginAirport(inboundAirport);
      // Verify Outcome
      assertEquals(0,flightsAtDestination1.size());
   }
Example TeardownFreeMultiResourceTest embedded from java/com/clrstream/ex6/services/test/ManualTeardownExampleTest.java
   protected void tearDown() throws Exception {
      try {
         facade.removeFlight( expFlightDto.getFlightNumber() );
      } finally {
         try {
            facade.removeAirport(inboundAirport);
         } finally  {
            facade.removeAirport(outboundAirport);
         }  
      }
   }
Example SafeMultiResourceImplicitTeardown embedded from java/com/clrstream/ex6/services/test/SafeMultiResourceImplicitTeardown.java

Note that there is no try/finally block around the exercising of the system under test (SUT) and the assertions. This helps the test reader understand that this is not an Expected Exception Test (see Test Method). Also, note that we didn't need to put a Guard Clause[SBPP] in front of each operation as the try/finally ensures that a failure is non-catastrophic so there is no real harm in going ahead and trying.



Page generated at Wed Feb 09 16:39:36 +1100 2011

Copyright © 2003-2008 Gerard Meszaros all rights reserved

All Categories
Introductory Narratives
Web Site Instructions
Code Refactorings
Database Patterns
DfT Patterns
External Patterns
Fixture Setup Patterns
Fixture Teardown Patterns
Front Matter
Glossary
Misc
References
Result Verification Patterns
Sidebars
Terminology
Test Double Patterns
Test Organization
Test Refactorings
Test Smells
Test Strategy
Tools
Value Patterns
XUnit Basics
xUnit Members
All "Fixture Teardown Patterns"
Garbage-Collected Teardown
Inline Teardown
Implicit Teardown
--Hooked Teardown
--Framework-invoked Teardown
--Teardown Method
Automated Teardown